package com.wen.common.exception;


import com.wen.common.enums.CodeEnum;
import com.wen.common.utils.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.ShiroException;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.method.HandlerMethod;
import org.thymeleaf.exceptions.TemplateInputException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 全局异常类
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    //日志
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    /**
     * 自定义业务异常
     *
     * @param request 请求
     * @param e       异常
     * @return 返回结果集到前端
     */
    @ExceptionHandler(CustomException.class)
//    @ResponseBody//返回json串
    public ResponseResult<?> myHandler(HttpServletRequest request, CustomException e) {
        logger.info("业务异常------code:[{}],msg:[{}]", e.getErrorCode(), e.getErrorMsg());
        return ResponseResult.error(e.getErrorCode(), e.getErrorMsg());
    }
    //用户密码错误
    @ExceptionHandler(value = IncorrectCredentialsException.class)
    public ResponseResult handler(IncorrectCredentialsException e) {
        return ResponseResult.error(CodeEnum.USER_NAME_PASSWD_ERROR);
    }
    //用户不存在
    @ExceptionHandler(UnknownAccountException.class)
    public ResponseResult<?> handler(UnknownAccountException e) {
        return ResponseResult.error(CodeEnum.USER_NAME_PASSWD_ERROR);
    }
    @ExceptionHandler(ExpiredCredentialsException.class)
    public ResponseResult<?> handler(ExpiredCredentialsException e) {
        return ResponseResult.error(CodeEnum.USER_TOKEN_INVALID);
    }
    @ExceptionHandler(LockedAccountException.class)
    public ResponseResult<?> handler(LockedAccountException e) {
        return ResponseResult.error(CodeEnum.USER_LOCK);
    }
    @ExceptionHandler(DisabledAccountException.class)
    public ResponseResult<?> handler(DisabledAccountException e) {
        return ResponseResult.error(CodeEnum.USER_IS_DELETE);
    }
    // 认证总异常
    @ExceptionHandler(AuthenticationException.class)
    public ResponseResult handler(AuthenticationException e) {
        log.error(" AuthenticationException : {}", e.getMessage());
        return ResponseResult.error(CodeEnum.USER_AUTHENTICATION_FAIL);
    }
    // 注解，匿名异常 ，多余
    @ExceptionHandler(UnauthenticatedException.class)
    public ResponseResult handler(UnauthenticatedException e) {
        log.error(" UnauthenticatedException : {}", e.getMessage());
        return ResponseResult.error(CodeEnum.USER_NOT_LOGGED_IN);
    }
    // 授权总异常
    @ExceptionHandler(AuthorizationException.class)
    public ResponseResult handler(AuthorizationException e) {
        log.error(" AuthorizationException : {}", e.getMessage());
        return ResponseResult.error(CodeEnum.USER_AUTHORIZATION_FAIL);
    }
    /**
     * shiro 权限异常
     */
    @ExceptionHandler({UnauthorizedException.class})
    public ResponseResult<?> handler(UnauthorizedException e) {
        if (e.getMessage().contains("permission")) {
            return ResponseResult.error(CodeEnum.USER_NOT_PERMISSIONS);
        }
        if (e.getMessage().contains("role")) {
            return ResponseResult.error(CodeEnum.USER_ROLE_NOT_EXIST);
        }
        return ResponseResult.error(CodeEnum.USER_PERMISSIONS_EXCEPTION);
    }

    /**
     * Shiro总异常
     */
    @ExceptionHandler(value = ShiroException.class)
    public ResponseResult handler(ShiroException e) {
        log.error("Shiro总异常：----------------{}", e.getMessage());
        return ResponseResult.error("401", e.getMessage());
    }
    @ResponseStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE)
    @ExceptionHandler(ArithmeticException.class)
    public String handler2(ArithmeticException e) {
        //日志显示
        logger.info("==============>" + e.getMessage());
        String message = e.getMessage();
        //控制台输出
        System.out.println("---------------------------------" + e.getMessage());
        //浏览器显示
        return "发生异常了" + message;
    }
    /**
     * 捕捉校验异常(BindException)
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(BindException.class)
    public ResponseResult<?> validException(BindException e) {
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        Map<String, Object> result = this.getValidError(fieldErrors);
        return ResponseResult.error("401", "错误信息？");
    }

    /**
     * 捕捉校验异常(MethodArgumentNotValidException)
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseResult<?> validException(MethodArgumentNotValidException e) {
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        Map<String, Object> result = this.getValidError(fieldErrors);
        return ResponseResult.error(HttpStatus.BAD_REQUEST.toString(), result.get("errorMsg").toString());
    }

    /**
     * 获取校验错误信息
     */
    private Map<String, Object> getValidError(List<FieldError> fieldErrors) {
        Map<String, Object> result = new HashMap<>(16);
        List<String> errorList = new ArrayList<>();
        StringBuffer errorMsg = new StringBuffer("校验异常(ValidException):");
        for (FieldError error : fieldErrors) {
            errorList.add(error.getField() + "-" + error.getDefaultMessage());
            errorMsg.append(error.getField()).append("-").append(error.getDefaultMessage()).append(".");
        }
        result.put("errorList", errorList);
        result.put("errorMsg", errorMsg);
        return result;
    }

    /**
     * Servlet异常    [请求方式异常，也在这里捕获]
     */
    @ExceptionHandler(value = ServletException.class)
    public ResponseResult handler(ServletException e, HttpServletRequest req) {
        String method = req.getMethod();
        log.error("请求方式异常：----------------{}", e.getMessage());
        return ResponseResult.error(CodeEnum.NOT_SUPPORTED.getResultCode(),
                method + CodeEnum.NOT_SUPPORTED.getResultMsg());
    }

    //任务点 ，处理这个渲染异常 ，文章在微信上面    ---没有作用
    @ExceptionHandler(value = TemplateInputException.class)
    public ResponseResult handler(TemplateInputException e) {
        log.error("渲染异常：----------------{}", e.getMessage());
        return ResponseResult.error("401", "渲染异常");
    }

    /**
     * 数据格式异常
     */
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public ResponseResult<?> handler(HttpMediaTypeNotSupportedException e) {
        log.error("数据格式异常：----------------{}", e.getMessage());
        return ResponseResult.error(CodeEnum.BODY_NOT_MATCH.getResultCode(), CodeEnum.BODY_NOT_MATCH.getResultMsg());
    }

    @ExceptionHandler(HttpClientErrorException.class)
    public ResponseResult<?> handler(HttpClientErrorException e) {
        return ResponseResult.error(CodeEnum.CLIENT_AUTH_ERROR);
    }

    /**
     * 运行时异常
     */
    @ExceptionHandler(value = RuntimeException.class)
    public ResponseResult handler(RuntimeException e) {
        log.error("运行时异常：----------------{}", e.getMessage());
        e.printStackTrace();
        return ResponseResult.error(CodeEnum.NOT_RUNNING.getResultCode(), CodeEnum.NOT_RUNNING.getResultMsg());
    }

    /**
     * 总异常
     */
    @ExceptionHandler(Exception.class) //声明这个类要处理的异常，和处理异常的类型
    public String exceptionHandler(Exception e, HandlerMethod method) {
        System.out.println("发生异常了...由exception捕获");
        String name = method.getMethod().getName();
        return name + "方法异常！" + "异常为：" + e.getMessage();
    }

}
